﻿package net.wangit.jdbc;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import net.wangit.Path;
import net.wangit.jdbc.config.JDBCSettings;
import net.wangit.jdbc.config.JDBCSettingsFactory;
import net.wangit.util.Checker;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * DB的工厂类。
 * 
 * @author watson Feb 12, 2010
 */
public class DBFactory {

	private static final Log log = LogFactory
			.getLog(net.wangit.jdbc.DBFactory.class);
	private static final ThreadLocal<Map<String, DB>> dbList = new ThreadLocal<Map<String, DB>>();
	private static final String DEFAULT_NAME = "app";

	// 关闭所有通过getDB()或getDB(String) 创建的数据库连接（系统调用）。
	protected static void closeAllDB() throws JDBCException {
		Map<String, DB> list;
		list = dbList.get();
		if (list == null)
			return;
		try {
			for (Iterator<DB> iter = list.values().iterator(); iter.hasNext();) {
				DB db = iter.next();
				if (db != null)
					db.close();
			}

			list.clear();
			if (log.isDebugEnabled())
				log.debug("all db are closed.");
		} catch (Exception e) {
			log.error("close all db failed!", e);
			e.printStackTrace();
		}
		return;
	}

	private static DBImpl create(String path) throws JDBCException {
		DBImpl db = new DBImpl();
		JDBCSettings js = JDBCSettingsFactory.getJDBCSettings(path);
		db.init(js);
		return db;
	}

	private static synchronized DBImpl get(String path, boolean cache)
			throws JDBCException {
		if (!cache)
			return create(path);
		Map<String, DB> list = dbList.get();
		if (list == null) {
			list = new HashMap<String, DB>();
			dbList.set(list);
		}
		DBImpl db = (DBImpl) list.get(path);
		if (db == null) {
			db = create(path);
			list.put(path, db);
		}
		return db;
	}

	// 使用数据源配置文件app.xml创建DB，
	// 如果当前进程中已存在则直接使用，不会重复创建，此方法获得的DB对象不需要手动关闭。
	public static DB getDB() throws JDBCException {
		return getDB(null, true);
	}

	// 使用指定的数据源配置文件创建DB，
	// 如果当前进程中已存在则直接使用，不会重复创建，此方法获得的DB对象不需要手动关闭。
	public static DB getDB(String name) throws JDBCException {
		return getDB(name, true);
	}

	private static DB getDB(String name, boolean cache) throws JDBCException {
		if (Checker.isEmpty(name))
			name = DBFactory.DEFAULT_NAME;
		int index = name.lastIndexOf("/");
		if (index > 0) {
			return getDomainDB(name.substring(0, index), cache);
		} else {
			String path = (new StringBuilder(Path.getDatasourcePath())).append(
					name).append(".xml").toString();
			return get(path, cache);
		}
	}

	// 取得指定的域数据库连接（系统调用）。
	protected static DBImplementor getDomainDB(String domain, boolean cache)
			throws JDBCException {
		String path = (new StringBuilder(Path.getDomainPath(domain))).append(
				"datasource.xml").toString();
		DBImpl db = get(path, cache);
		return db;
	}

	// 使用数据源配置文件app.xml创建DB，每次调用时创建一个新的DB，此方法获得的DB对象必须手动关闭。
	public static DB newDB() throws JDBCException {
		return getDB(null, false);
	}

	// 使用指定的数据源配置文件创建DB，每次调用时创建一个新的DB，此方法获得的DB对象必须手动关闭。
	public static DB newDB(String name) throws JDBCException {
		return getDB(name, false);
	}

	public DBFactory() {
	}

}
